/**
 * 网站启动的主功能模块
 */

var express = require('express');
var app = express();

var websiteConfig = require('./bin/getConfig')('config/website.json');

// rootUrl
var rootUrl = websiteConfig.rootUrl;

app.set('trust proxy', 1);

// ejs renderer
var ejs = require('ejs');
app.engine('html', ejs.__express);
app.set('views', 'public');
app.set('view engine', 'html');

// static files of .ico/.img/.js/.css/......
var statics = websiteConfig.statics;
statics.forEach((stat) => {
    app.use(rootUrl + stat.route, express.static(stat.dir, {index:false, fallthrough:false}));
});

// static files in public, favicon.ico
var publicMidware = express.static('public', {index:false});
app.use(rootUrl, function(req, res, next){
    let pos = req.url.indexOf('?');
    let url = pos<0 ? req.url : req.url.substring(0, pos);
    if (url.substr(-5) === '.html'){
        next();
        return;
    }
    //注意： favicon.ico 谷歌浏览器修改了加载策略，只有 http 开头，且域名不带端口号才能用
    publicMidware(req, res, next);
});

// log on console
var logger = require('morgan');
app.use(logger('dev'));

// 拦截POST无referer的情况
app.use(function(req, res, next){
    if (req.method !== 'GET' && req.headers.referer == null){
        res.end('Hack-Like access, your ip has been recorded, rights reserved.');
        return;
    }
    next();
});

// GET :parse url params and make json
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

// POST :parse url params and make json
var bodyparser = require('body-parser');
app.use(bodyparser.json()); // 使用bodyparder中间件，
app.use(bodyparser.urlencoded({ extended: true }));

var cookieParser = require('cookie-parser');
app.use(cookieParser());

// session
var monitorMidware = require('./bin/session-monitor-middleware')();
var redisentityTool = require('./bin/redisentity');
var session = require('./bin/session');
app.use(session({
    getUserid : (user) => user._id,
    getUsername : (user) => user.nickname,
    getData : redisentityTool.get,
    setData : redisentityTool.set,
    midwares : [ monitorMidware ]
}));

var behavior = require('./bin/behavior');
app.use(behavior());

app.use((req, res, next) => {
    res.locals.rootUrl = rootUrl;
    next();
});

var blockMidware = require('./bin/block-middleware');
app.use(rootUrl, blockMidware);

var componentMidware = require('./bin/component-middleware');
app.use(rootUrl, componentMidware('public', /(?<=^com\.).*(?=\.html$)/, true));

var pkgAdapter = require('./pkg-adapter');
var routesPath = pkgAdapter.getFullPath('routes');

// load routes
var staticRouterMidware = require('./bin/static-router-middleware');
staticRouterMidware(app, rootUrl, routesPath, /(?<!^dyn\.).*\.js$/);

// default .html page
var autoEjsRender = require('./bin/auto-ejs-render');
app.use(rootUrl, autoEjsRender('public'));

var dynamicRouterMidware = require('./bin/dynamic-router-middleware'); // 动态路由匹配，如：路由'/articlepublic' 可匹配 '/[任意板块]/articlepublic'
app.use(rootUrl, dynamicRouterMidware(routesPath, /(?<=^dyn\.).*\.js$/));

// catch 404 and forward to error handler
var createError = require('http-errors');
app.use(function(req, res, next) {
    if (! (req.currentError instanceof Error)){
        req.currentError = createError(404);
    }
    next();
});

// error handler
app.use(function(req, res) {
    // set locals, only providing error in development
    let err = req.currentError;
    res.locals.message = err.message;
    res.locals.error = req.app.get('env') === 'development' ? err : {};

    // render the error page
    res.status(err.status || 500);
    res.render('error');
});

// uncaught exception
process.on('uncaughtException', function(ex){
    console.log(ex);
});

module.exports = app;
